package com.ea.eadp.nexus.test.common.ApiClients;

import static com.ea.eadp.nexus.test.common.Constant.ORIGINNAMESPACE;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;

import com.ea.eadp.nexus.client.nucleus.identity.IdentityClientApi;
import com.ea.eadp.nexus.client.nucleus.identity.model.*;
import com.ea.eadp.nexus.test.common.SystemProperties;
import com.ea.eadp.nexus.test.common.TestUtil;
import com.ea.eadp.rest.identity.generated.client.pidprofile.PostPidUserProfileInfoRequest;
import com.ea.eadp.test.shared.utility.RandomFactory;
import com.ea.eadp.test.shared.workflow.identity.twoFactor.CalculateTwoFactorCodeWorkflowElement;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;

import com.ea.eadp.nexus.client.nucleus.identity.IdentityClientApi;
import com.ea.eadp.nexus.client.nucleus.identity.model.BackupCodesType;
import com.ea.eadp.nexus.client.nucleus.identity.model.CreateUserProfileApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.CreateUserProfileApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.DeleteUserProfileApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.DeleteUserProfileApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.EntitlementPostApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.EntitlementPostApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.EntitlementRequestType;
import com.ea.eadp.nexus.client.nucleus.identity.model.GetAuthTokenApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.GetAuthTokenApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.GetPersonaNamesApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.GetPersonaNamesApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.MachineProfileCheckVerifiedApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.MachineProfileCheckVerifiedApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.MachineProfileUpdateStatusApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.MachineProfileUpdateStatusApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.MachineProfileUpdateStatusRequestType;
import com.ea.eadp.nexus.client.nucleus.identity.model.PSNRefreshTokenRequestType;
import com.ea.eadp.nexus.client.nucleus.identity.model.PersonaCreateApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.PersonaCreateApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.PersonaExtrefPostApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.PersonaExtrefPostApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.PersonaSearchApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.PersonaSearchApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.PersonaSearchByPidApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.PersonaSearchByPidApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.PidGetApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.PidGetApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.PidGetSecuritystateApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.PidGetSecuritystateApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.PidPersonaType;
import com.ea.eadp.nexus.client.nucleus.identity.model.PidProfileEntryType;
import com.ea.eadp.nexus.client.nucleus.identity.model.PidProfilePostRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.PidProfileRequestType;
import com.ea.eadp.nexus.client.nucleus.identity.model.PidRegisterApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.PidRegisterApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.PidSearchApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.PidSearchApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.PidType;
import com.ea.eadp.nexus.client.nucleus.identity.model.PostAuthTokenApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.PostAuthTokenApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.PostPersonaRequestType;
import com.ea.eadp.nexus.client.nucleus.identity.model.PrivacySettingsGetApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.PrivacySettingsGetApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.PrivacySettingsPostApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.PrivacySettingsPostApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.PsnrefreshtokenPostApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.PsnrefreshtokenPostApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.SearchEmailPreferencesApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.SearchEmailPreferencesApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.SearchUserProfileApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.SearchUserProfileApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.SecurityQAProfileRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwoFactorBackupCodeType;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwoFactorPostRequestType;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwoFactorStatusType;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwoFactorType;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwoFactorVerifyCodeRequestType;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwoPhaseRegistrationRecordType;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwofactorGetApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwofactorPostApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwofactorbackupcodeGetApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwofactorbackupcodeGetApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwofactorbackupcodePostApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwofactorcodeGetApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwofactorcodeGetApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwofactorcodeVerifyApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwofactorcodeVerifyApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwofactorstatusPutApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwophaseregGetByUseridApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.TwophaseregGetByUseridApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.UpdatePidApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.UpdatePidApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.UsercodeGetByUseridApiRequest;
import com.ea.eadp.nexus.client.nucleus.identity.model.UsercodeGetByUseridApiResponse;
import com.ea.eadp.nexus.client.nucleus.identity.model.pidPrivacySettingsType;
import com.ea.eadp.nexus.test.common.SystemProperties;
import com.ea.eadp.nexus.test.common.TestUtil;

/**
 * Created by ChuanYe on 7/24/2014.
 */
public class NucleusApi extends NexusApiBase {
    private static NucleusApi instance;

    public enum PasswordStrength {
        STRONG,
        WEAK,
    }

    private String defaultRegionCode = "US";

    public synchronized static NucleusApi instance() {
        if (instance == null) {
            instance = new NucleusApi();
        }
        instance.client = NexusHttpClients.getNucleusClient();
        return instance;
    }

    private IdentityClientApi getIdentityClientApi() {
        IdentityClientApi identityClientApi = new IdentityClientApi();
        identityClientApi.setHttpClient(client);
        identityClientApi.setBasePath(SystemProperties.instance().getProperty(SystemProperties.IdentityPortalUri));
        Map<String, String> map = new HashMap<String, String>();
        map.put("Nucleus-RequestorId", "Integration-Tests");
        identityClientApi.setDefaultHeaderMap(map);
        return identityClientApi;
    }

    public String postPid(String email, String password) throws Exception {
        return postPid(email, password, PasswordStrength.STRONG);
    }

    public String postPid(String email, String password, PasswordStrength strength) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();

        PidRegisterApiRequest apiRequest = new PidRegisterApiRequest();
        PidType pidType = new PidType();
        pidType.setEmail(email);
        pidType.setCountry(defaultRegionCode);
        pidType.setDob("1990-01-01");
        pidType.setPassword(password);
        pidType.setStrength(strength.name());
        pidType.setLanguage("en");
        pidType.setTosVersion("666");
        pidType.setGlobalOptin("false");
        pidType.setThirdPartyOptin("false");
        pidType.setStatus("ACTIVE");
        apiRequest.setPayload(pidType);

        PidRegisterApiResponse pidRegisterApiResponse = identityClientApi.executePidRegister(apiRequest);
        if (pidRegisterApiResponse.getHttpResponseCode() != 200) {
            throw new Exception("register pid failed");
        }
        return pidRegisterApiResponse.getPidUri();
    }

    public String postUKPid(String email, String password) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();

        PidRegisterApiRequest apiRequest = new PidRegisterApiRequest();
        PidType pidType = new PidType();
        pidType.setEmail(email);
        pidType.setCountry("GB");
        pidType.setDob("1990-01-01");
        pidType.setPassword(password);
        pidType.setStrength("STRONG");
        pidType.setLanguage("en");
        pidType.setTosVersion("666");
        pidType.setGlobalOptin("false");
        pidType.setThirdPartyOptin("false");
        pidType.setStatus("ACTIVE");
        apiRequest.setPayload(pidType);

        PidRegisterApiResponse pidRegisterApiResponse = identityClientApi.executePidRegister(apiRequest);
        if (pidRegisterApiResponse.getHttpResponseCode() != 200) {
            throw new Exception("register pid failed");
        }
        return pidRegisterApiResponse.getPidUri();
    }

    public String postUKUnderEighteenPid(String email, String password) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();

        PidRegisterApiRequest apiRequest = new PidRegisterApiRequest();
        PidType pidType = new PidType();
        pidType.setEmail(email);
        pidType.setCountry("GB");

        // 1 day after 18 years ago
        Calendar DOB = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        DOB.add(Calendar.YEAR, -15);
        DOB.add(Calendar.DATE, 1);
        SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
        pidType.setDob(dateFormatter.format(DOB.getTime()));

        pidType.setPassword(password);
        pidType.setStrength("STRONG");
        pidType.setLanguage("en");
        pidType.setTosVersion("666");
        pidType.setGlobalOptin("false");
        pidType.setThirdPartyOptin("false");
        pidType.setStatus("ACTIVE");
        apiRequest.setPayload(pidType);

        PidRegisterApiResponse pidRegisterApiResponse = identityClientApi.executePidRegister(apiRequest);
        if (pidRegisterApiResponse.getHttpResponseCode() != 200) {
            throw new Exception("register pid failed");
        }
        return pidRegisterApiResponse.getPidUri();
    }

    public String postMinorPid(String email, String password) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();

        PidRegisterApiRequest apiRequest = new PidRegisterApiRequest();
        PidType pidType = new PidType();
        pidType.setEmail(email);
        pidType.setParentalEmail(TestUtil.getRandomEmail());
        Calendar cal = Calendar.getInstance();
        int year = cal.get(Calendar.YEAR) - 10;
        String date = year + "-01-01";
        pidType.setDob(date);

        pidType.setCountry(defaultRegionCode);
        pidType.setPassword(password);
        pidType.setLanguage("en");
        pidType.setTosVersion("666");
        pidType.setGlobalOptin("true");
        pidType.setThirdPartyOptin("false");
        pidType.setStatus("CHILD_PENDING");
        apiRequest.setPayload(pidType);

        PidRegisterApiResponse pidRegisterApiResponse = identityClientApi.executePidRegister(apiRequest);
        if (pidRegisterApiResponse.getHttpResponseCode() != 200) {
            throw new Exception("register pid failed");
        }
        return pidRegisterApiResponse.getPidUri();
    }

    public String postPidWithWeakPassword(String email) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();

        PidRegisterApiRequest apiRequest = new PidRegisterApiRequest();
        PidType pidType = new PidType();
        pidType.setEmail(email);
        pidType.setCountry(defaultRegionCode);
        pidType.setDob("1990-01-01");
        pidType.setPassword("1234");
        pidType.setStrength("WEAK");
        pidType.setLanguage("en");
        pidType.setTosVersion("666");
        pidType.setGlobalOptin("false");
        pidType.setThirdPartyOptin("false");
        pidType.setStatus("ACTIVE");
        apiRequest.setPayload(pidType);

        PidRegisterApiResponse pidRegisterApiResponse = identityClientApi.executePidRegister(apiRequest);
        if (pidRegisterApiResponse.getHttpResponseCode() != 200) {
            throw new Exception("register pid failed: " + pidRegisterApiResponse.toString());
        }
        return pidRegisterApiResponse.getPidUri();
    }

    public String postPersona(Long pidId, String displayName) throws Exception {
        return postPersona(pidId, displayName, ORIGINNAMESPACE);
    }

    public String postPersona(Long pidId, String displayName, String namespaceName) throws Exception {
        PostPersonaRequestType postPersonaRequestType = new PostPersonaRequestType();
        postPersonaRequestType.setDisplayName(displayName);
        postPersonaRequestType.setNamespaceName(namespaceName);
        postPersonaRequestType.setStatus("Active");

        PersonaCreateApiRequest personaRequest = new PersonaCreateApiRequest();
        personaRequest.setPersona(postPersonaRequestType);
        personaRequest.setPidId(pidId);

        IdentityClientApi identityClientApi = getIdentityClientApi();

        PersonaCreateApiResponse response = identityClientApi.executePersonaCreate(personaRequest);
        if (response.getHttpResponseCode() != 200) {
            throw new Exception("post persona failed:"+response.toString());
        }
        return response.getPersonaUri();
    }
    public String getPidUriByEmail(String email) {
       return   getPidUriByEmail(email, false, false);
    }

    public String getPidUriByEmail(String email,boolean isInclude_Incomplete,boolean isInclude_Underage) {
        IdentityClientApi identityClientApi = getIdentityClientApi();

        PidSearchApiRequest pidSearchApiRequest = new PidSearchApiRequest();
        pidSearchApiRequest.setX_Include_Incomplete(isInclude_Incomplete);
        pidSearchApiRequest.setX_Include_Underage(isInclude_Underage);
        pidSearchApiRequest.setEmail(email);
        PidSearchApiResponse pidSearchApiResponse = identityClientApi.executePidSearch(pidSearchApiRequest);
        if (pidSearchApiResponse.getPids().getPidUri() != null) {
            return pidSearchApiResponse.getPids().getPidUri().get(0);
        } else {
            return null;
        }
    }

    public String getPidUriByOriginId(String originId) {

        if (originId != null) {
            IdentityClientApi identityClientApi = getIdentityClientApi();
            PersonaSearchApiRequest personaSearchApiRequest = new PersonaSearchApiRequest();
            personaSearchApiRequest.setDisplayName(originId);

            PersonaSearchApiResponse response = identityClientApi.executePersonaSearch(personaSearchApiRequest);
            if (response.getPersonas() != null) {
                return response.getPersonas().getPersonaUri().get(0);
            } else {
                return null;
            }

        }
        return null;

    }

    public MachineProfileCheckVerifiedApiResponse getMachineProfile(String pidID,
                                                                    String deviceId, String platformType, String profileType) throws Exception {
        IdentityClientApi api = getIdentityClientApi();
        MachineProfileCheckVerifiedApiRequest requestType = new MachineProfileCheckVerifiedApiRequest();
        requestType.setPidId(pidID);
        requestType.setMachineProfile(deviceId);
        requestType.setPlatformType(platformType);
        requestType.setProfileType(profileType);
        return api.executeMachineProfileCheckVerified(requestType);
    }

    public MachineProfileUpdateStatusApiResponse updateMachineProfile(String pidID,
                                                                    String deviceId, String platformType, String profileType,String status,Map<String,String> hread) throws Exception {
        IdentityClientApi api = getIdentityClientApi();
        api.setDefaultHeaderMap(hread);
        MachineProfileUpdateStatusApiRequest request = new MachineProfileUpdateStatusApiRequest();
        MachineProfileUpdateStatusRequestType requestType=new MachineProfileUpdateStatusRequestType();
        requestType.setMachineProfile(deviceId);
        requestType.setPlatformType(platformType);
        requestType.setProfileType(profileType);
        requestType.setStatus(status);
        request.setPidId(pidID);
        request.setMachineProfile(requestType);
        return api.executeMachineProfileUpdateStatus(request);
    }

    public PidPersonaType getPersona(Long pidId, String displayName, String namespace) throws Exception {
        PersonaSearchByPidApiRequest request = new PersonaSearchByPidApiRequest();
        request.setPidId(pidId);
        request.setDisplayName(displayName);
        request.setNamespaceName(namespace);
        request.setX_Expand_Results(true);
        IdentityClientApi identityClientApi = getIdentityClientApi();
        PersonaSearchByPidApiResponse response = identityClientApi.executePersonaSearchByPid(request);
        if (response.getHttpResponseCode() != 200) {
            throw new Exception("post persona failed");
        }
        return response.getPersonas().getPersona() != null ? response.getPersonas().getPersona().get(0) : null;
    }

    public PidPersonaType getPersonaByDisplayName(String displayName) throws Exception {
        PersonaSearchApiRequest request = new PersonaSearchApiRequest();
        request.setDisplayName(displayName);
        request.setX_Expand_Results(true);
        IdentityClientApi identityClientApi = getIdentityClientApi();
        PersonaSearchApiResponse response = identityClientApi.executePersonaSearch(request);
        if (response.getHttpResponseCode() != 200) {
            throw new Exception("post persona failed");
        }
        return response.getPersonas().getPersona() != null ? response.getPersonas().getPersona().get(0) : null;
    }

    public PidPersonaType getOriginId(Long pidId) throws Exception {
        GetPersonaNamesApiRequest request = new GetPersonaNamesApiRequest();
        request.setPidId(pidId.toString());
        request.setNamespaceName("cem_ea_id");
        request.setX_Expand_Results(true);

        IdentityClientApi identityClientApi = getIdentityClientApi();

        GetPersonaNamesApiResponse response = identityClientApi.executeGetPersonaNames(request);
        if (response.getHttpResponseCode() != 200) {
            throw new Exception("get persona failed");
        }
        return response.getPersonas().getPersona() != null ? response.getPersonas().getPersona().get(0) : null;
    }

    public PidInfoType getPidInfo(Long pidId) throws Exception {
        PidInfoGetApiRequest pidInfoGetApiRequest=new PidInfoGetApiRequest();
        pidInfoGetApiRequest.setPidId(pidId);
        pidInfoGetApiRequest.setNucleus_RequestorId("dev");

        IdentityClientApi identityClientApi = getIdentityClientApi();

        PidInfoGetApiResponse response = identityClientApi.executePidInfoGet(pidInfoGetApiRequest);
        if (response.getHttpResponseCode() != 200) {
            throw new Exception("get PidInfoType failed");
        }
        return response.getPidInfo();
    }

    public String postEntitlement(Long pidId, String groupName) throws Exception {
        EntitlementPostApiRequest request = new EntitlementPostApiRequest();

        EntitlementRequestType entitlementRequestType = new EntitlementRequestType();
        entitlementRequestType.setEntitlementType("ORIGIN_DOWNLOAD");
        entitlementRequestType.setStatus("ACTIVE");
        entitlementRequestType.setEntitlementTag("MY_FAVORITE_ENTITLEMENT");
        entitlementRequestType.setGroupName(groupName);
        entitlementRequestType.setEntitlementSource("TestSource");

        request.setPayload(entitlementRequestType);
        request.setPidId(pidId.toString());

        IdentityClientApi identityClientApi = getIdentityClientApi();

        EntitlementPostApiResponse response = identityClientApi.executeEntitlementPost(request);
        if (response.getHttpResponseCode() != 200) {
            throw new Exception("post entitlement failed");
        }
        return response.getEntitlementUri();
    }

    public String postPidExternalRef(Long pidId, String type, String value) throws Exception {
        ExternalReferenceRequestType requestType = new ExternalReferenceRequestType();
        requestType.setExternalRefType(type);
        requestType.setExternalRefValue(value);

        ExtrefPostApiRequest request = new ExtrefPostApiRequest();
        request.setPidId(String.valueOf(pidId));
        request.setValue(requestType);

        IdentityClientApi identityClientApi = getIdentityClientApi();
        ExtrefPostApiResponse response = identityClientApi.executeExtrefPost(request);

        if (response.getHttpResponseCode() != 200) {
            throw new Exception("post persona extref failed");
        }
        return response.getExternalRefUri();
    }

    public String postPersonaExternalRef(Long personaId, String value, String type) throws Exception {
        PersonaExtrefPostApiRequest request = new PersonaExtrefPostApiRequest();

        request.setPersonaId(personaId);
        request.setExternalRefType(type);
        request.setExternalRefValue(value);

        IdentityClientApi identityClientApi = getIdentityClientApi();
        PersonaExtrefPostApiResponse response = identityClientApi.executePersonaExtrefPost(request);

        if (response.getHttpResponseCode() != 200) {
            throw new Exception("post persona extref failed");
        }
        return response.getPersonaReference().getPersonaUri();
    }

    public String[] getPersonaExternalRefByRefTypeAndValue(String value, String type) throws Exception {
        String baseUrl = SystemProperties.instance().getProperty(SystemProperties.IdentityPortalUri);
        String url = baseUrl + "/personas/externalref?externalRefType=" + type + "&externalRefValue=" + value;
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Nucleus-RequestorId", "Integration-Tests");
        HttpResponse response = get(httpGet, null);

        String body = IOUtils.toString(response.getEntity().getContent());
        log.info("RESPONSE BODY: " + body);
        int status = response.getStatusLine().getStatusCode();
        if (status != 200) {
            throw new Exception("get persona external ref with value " + value + "failed!");
        }
        if (body.compareTo("{ }") == 0)
            return null;
        //todo: take list into consideration and use json parse
        String personaId = body.substring(body.indexOf("personas") + 9, body.indexOf("externalref") - 1);
        String refId = body.substring(body.indexOf("externalref") + 12, body.lastIndexOf('/'));

        String[] result = new String[2];
        result[0] = personaId;
        result[1] = refId;
        return result;
    }

    public void deletePersonaExternalRefByPersonaAndRefId(String personaId, String refId) throws Exception {
        String baseUrl = SystemProperties.instance().getProperty(SystemProperties.IdentityPortalUri);
        String url = baseUrl + "/personas/" + personaId + "/externalref/" + refId;
        HttpDelete httpDelete = new HttpDelete(url);
        httpDelete.setHeader("Nucleus-RequestorId", "Integration-Tests");
        delete(httpDelete, null);
        HttpResponse response = delete(httpDelete, null);

        String body = IOUtils.toString(response.getEntity().getContent());
        log.info("RESPONSE BODY: " + body);
        //comment currently: there is bug in the delete API, always return no such persona reference even it is deleted successfuly
        //int status = response.getStatusLine().getStatusCode();
        //if (status != 200) {
        //  throw new Exception("delete persona external ref with id " + refId + "failed!" );
        //}
    }


    /*
     * at present, the behavior of POST and PUT is same somehow in the SECURITY_QA category
     * nobody can really tell whether this is correct or not
     *
     * in this way, the last few question/answer would take effect as the previous ones are
     * overwritten
     *
     * TODO verifying
     */
    public Set<String> postSecurityQA(Long pidId, Map<String, String> securityQA) throws Exception {
        Set<String> result = new HashSet<String>();
        IdentityClientApi identityClientApi = getIdentityClientApi();
        Iterator<String> questionIterator = securityQA.keySet().iterator();

        while (questionIterator.hasNext()) {
            SecurityQAProfileRequest securityQAProfileRequest = new SecurityQAProfileRequest();
            String question = null;

            if (questionIterator.hasNext()) {
                question = questionIterator.next();
                securityQAProfileRequest.setSec_question(question);
                securityQAProfileRequest.setSec_answer(securityQA.get(question));
            }

            if (questionIterator.hasNext()) {
                question = questionIterator.next();
                securityQAProfileRequest.setSec_question2(question);
                securityQAProfileRequest.setSec_answer2(securityQA.get(question));
            }

            if (questionIterator.hasNext()) {
                question = questionIterator.next();
                securityQAProfileRequest.setSec_question3(question);
                securityQAProfileRequest.setSec_answer3(securityQA.get(question));
            }

            PidProfileRequestType pidProfileRequestType = new PidProfileRequestType();
            pidProfileRequestType.setSecurityQAInfo(securityQAProfileRequest);

            PidProfilePostRequest pidProfilePostRequest = new PidProfilePostRequest();
            pidProfilePostRequest.setProfileInfoCategory("SECURITY_QA");
            pidProfilePostRequest.setProfileInfo(pidProfileRequestType);

            CreateUserProfileApiRequest request = new CreateUserProfileApiRequest();
            request.setPayload(pidProfilePostRequest);
            request.setPidId(pidId.toString());

            CreateUserProfileApiResponse response = identityClientApi.executeCreateUserProfile(request);

            if (response.getHttpResponseCode() != 200) {
                throw new Exception("post security qa failed: " + response.getError());
            }

            result.add(response.getPidProfileUri());
        }

        return result;
    }

    public String postSecurityQA(Long pidId) throws Exception {
        Map<String, String> securityQA = new HashMap<String, String>();
        securityQA.put("Where did your parents meet?", "answer");

        return postSecurityQA(pidId, securityQA).iterator().next();
    }

    public void postName(Long pidId) throws Exception{
        IdentityClientApi identityClientApi = getIdentityClientApi();

        NameProfileRequest nameProfileRequest = new NameProfileRequest();
        nameProfileRequest.setFirst_name(RandomFactory.getRandomStringOfAlphabet(10));
        nameProfileRequest.setLast_name(RandomFactory.getRandomStringOfAlphabet(10));

        PidProfileRequestType pidProfileRequestType = new PidProfileRequestType();
        pidProfileRequestType.setNameInfo(nameProfileRequest);

        PidProfilePostRequest pidProfilePostRequest = new PidProfilePostRequest();
        pidProfilePostRequest.setProfileInfoCategory("NAME");
        pidProfilePostRequest.setProfileInfo(pidProfileRequestType);

        CreateUserProfileApiRequest request = new CreateUserProfileApiRequest();
        request.setPayload(pidProfilePostRequest);
        request.setPidId(pidId.toString());

        CreateUserProfileApiResponse response = identityClientApi.executeCreateUserProfile(request);

        if (response.getHttpResponseCode() != 200) {
            throw new Exception("post name failed: " + response.getError());
        }
    }

    public Set<PidProfileEntryType> getUserProfiles(Long pid, String profileInfoCategory) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();

        SearchUserProfileApiRequest request = new SearchUserProfileApiRequest();
        request.setX_Expand_Results(true);
        request.setPidId(pid.toString());
        request.setProfileInfoCategory(profileInfoCategory);

        SearchUserProfileApiResponse response = identityClientApi.executeSearchUserProfile(request);

        if (response.getHttpResponseCode() != 200) {
            throw new Exception("get pid profile failed: " + response.getError());
        }

        return new HashSet<PidProfileEntryType>(response.getPidProfiles().getPidProfileEntry());
    }

    public void deleteUserProfiles(Long pid, String profileInfoCategory) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();
        Set<PidProfileEntryType> entries = getUserProfiles(pid, profileInfoCategory);

        DeleteUserProfileApiResponse response = null;
        DeleteUserProfileApiRequest request = new DeleteUserProfileApiRequest();
        request.setPidId(pid.toString());

        for (PidProfileEntryType entry : entries) {
            request.setProfileInfoCategory(entry.getEntryCategory());
            request.setEntryId(entry.getEntryId().toString());

            response = identityClientApi.executeDeleteUserProfile(request);

            if (response.getHttpResponseCode() != 200) {
                throw new Exception("get pid profile failed: " + response.getError());
            }
        }
    }

    public void deleteUserSecurityQuestionAndAnswer(Long pid) throws Exception {
        deleteUserProfiles(pid, "SECURITY_QA");
    }

    public String postAuthToken(String email, String password) throws Exception {
        PostAuthTokenApiRequest postAuthTokenApiRequest = new PostAuthTokenApiRequest();
        postAuthTokenApiRequest.setDuration("5");
        postAuthTokenApiRequest.setEmail(email);
        postAuthTokenApiRequest.setPassword(password);
        IdentityClientApi identityClientApi = getIdentityClientApi();
        PostAuthTokenApiResponse response = identityClientApi.executePostAuthToken(postAuthTokenApiRequest);
        if (response.getHttpResponseCode() != 200) {
            throw new Exception("post authtoken failed");
        }
        return response.getAuthTokenUri();
    }

    public Long getAuthToken(String accessToken) throws Exception {
        GetAuthTokenApiRequest getAuthTokenApiRequest = new GetAuthTokenApiRequest();
        getAuthTokenApiRequest.setAuthToken(accessToken);
        IdentityClientApi identityClientApi = getIdentityClientApi();
        GetAuthTokenApiResponse response = identityClientApi.executeGetAuthToken(getAuthTokenApiRequest);
        if (response.getHttpResponseCode() != 200) {
            throw new Exception("get authtoken failed");
        }
        return response.getAuthToken().getUserId();
    }

    public void validatePidAgeUpStatus(Long pid) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();

        PidGetApiRequest request = new PidGetApiRequest();
        request.setX_Include_Underage(true);
        request.setPidId(pid);

        PidGetApiResponse response = identityClientApi.executePidGet(request);
        if (response.getHttpResponseCode() != 200) {
            throw new Exception("register pid failed");
        }
        if (!response.getPid().getStatus().equals("ACTIVE")) {
            throw new Exception("age up user status error");
        }
    }

    public String postUnderAgePid(String parentEmail, String password) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();

        PidRegisterApiRequest apiRequest = new PidRegisterApiRequest();
        PidType pidType = new PidType();
        pidType.setParentalEmail(parentEmail);
        pidType.setCountry(defaultRegionCode);

        int year = Calendar.getInstance().get(Calendar.YEAR);

        pidType.setDob(year - 12 + "-01-01");
        pidType.setPassword(password);
        pidType.setStrength("STRONG");
        pidType.setLanguage("en");
        pidType.setTosVersion("666");
        pidType.setGlobalOptin("true");
        pidType.setThirdPartyOptin("false");
        pidType.setStatus("ACTIVE");
        pidType.setAnonymousPid("true");
        pidType.setRegistrationSource("dev");
        apiRequest.setPayload(pidType);

        PidRegisterApiResponse pidRegisterApiResponse = identityClientApi.executePidRegister(apiRequest);
        if (pidRegisterApiResponse.getHttpResponseCode() != 200) {
            throw new Exception("register pid failed");
        }
        return pidRegisterApiResponse.getPidUri();
    }

    public String postUnderEighteenPid(String email, String password) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();

        PidRegisterApiRequest apiRequest = new PidRegisterApiRequest();
        PidType pidType = new PidType();
        pidType.setEmail(email);
        pidType.setCountry(defaultRegionCode);

        // 1 day after 18 years ago
        Calendar DOB = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        DOB.add(Calendar.YEAR, -15);
        DOB.add(Calendar.DATE, 1);
        SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
        dateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
        pidType.setDob(dateFormatter.format(DOB.getTime()));

        pidType.setPassword(password);
        pidType.setStrength("STRONG");
        pidType.setLanguage("en");
        pidType.setTosVersion("666");
        pidType.setGlobalOptin("false");
        pidType.setThirdPartyOptin("false");
        pidType.setStatus("ACTIVE");
        apiRequest.setPayload(pidType);

        PidRegisterApiResponse pidRegisterApiResponse = identityClientApi.executePidRegister(apiRequest);
        if (pidRegisterApiResponse.getHttpResponseCode() != 200) {
            throw new Exception("register pid failed");
        }
        return pidRegisterApiResponse.getPidUri();
    }

    public String postUnderAgePidWithWeakPassword(String parentEmail) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();

        PidRegisterApiRequest apiRequest = new PidRegisterApiRequest();
        PidType pidType = new PidType();
        pidType.setParentalEmail(parentEmail);
        pidType.setCountry(defaultRegionCode);

        int year = Calendar.getInstance().get(Calendar.YEAR);

        pidType.setDob(year - 12 + "-01-01");
        pidType.setPassword("1234");
        pidType.setStrength("WEAK");
        pidType.setLanguage("en");
        pidType.setTosVersion("666");
        pidType.setGlobalOptin("true");
        pidType.setThirdPartyOptin("false");
        pidType.setStatus("ACTIVE");
        pidType.setAnonymousPid("true");
        pidType.setRegistrationSource("dev");
        apiRequest.setPayload(pidType);

        PidRegisterApiResponse pidRegisterApiResponse = identityClientApi.executePidRegister(apiRequest);
        if (pidRegisterApiResponse.getHttpResponseCode() != 200) {
            throw new Exception("register pid failed");
        }
        return pidRegisterApiResponse.getPidUri();
    }

    public String postUnderAgePidForMobile(String email, String password) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();

        PidRegisterApiRequest apiRequest = new PidRegisterApiRequest();
        PidType pidType = new PidType();
        pidType.setEmail(email);
        pidType.setParentalEmail(TestUtil.getRandomEmail());
        pidType.setCountry(defaultRegionCode);

        int year = Calendar.getInstance().get(Calendar.YEAR);

        pidType.setDob(year - 12 + "-01-01");
        pidType.setPassword(password);
        pidType.setStrength("STRONG");
        pidType.setLanguage("en");
        pidType.setTosVersion("666");
        pidType.setGlobalOptin("true");
        pidType.setThirdPartyOptin("false");
        pidType.setStatus("ACTIVE");
        pidType.setAnonymousPid("false");
        pidType.setRegistrationSource("dev");
        apiRequest.setPayload(pidType);

        PidRegisterApiResponse pidRegisterApiResponse = identityClientApi.executePidRegister(apiRequest);
        if (pidRegisterApiResponse.getHttpResponseCode() != 200) {
            throw new Exception("register pid failed");
        }
        return pidRegisterApiResponse.getPidUri();
    }

    public String postPogoAnonymousPid(String password) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();

        PidRegisterApiRequest apiRequest = new PidRegisterApiRequest();
        PidType pidType = new PidType();
        pidType.setCountry(defaultRegionCode);
        pidType.setDob("1990-01-01");
        pidType.setPassword(password);
        pidType.setStrength("STRONG");
        pidType.setLanguage("en");
        pidType.setTosVersion("666");
        pidType.setGlobalOptin("false");
        pidType.setThirdPartyOptin("false");
        pidType.setStatus("ACTIVE");
        pidType.setAnonymousPid("true");
        pidType.setRegistrationSource("pogo");
        apiRequest.setPayload(pidType);

        PidRegisterApiResponse pidRegisterApiResponse = identityClientApi.executePidRegister(apiRequest);
        if (pidRegisterApiResponse.getHttpResponseCode() != 200) {
            throw new Exception("register pid failed");
        }
        return pidRegisterApiResponse.getPidUri();
    }

    public String postPidAndPersonaIfNotExisted(String email, String password, String originId, String namespace) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();

        PidSearchApiRequest pidSearchApiRequest = new PidSearchApiRequest();
        pidSearchApiRequest.setEmail(email);
        PidSearchApiResponse pidSearchApiResponse = identityClientApi.executePidSearch(pidSearchApiRequest);
        if (pidSearchApiResponse.getPids().getPidUri() != null) {
            return pidSearchApiResponse.getPids().getPidUri().get(0);
        }

        String pidUri = postPid(email, password);
        String pid = pidUri.split("/")[2];
        postPersona(Long.parseLong(pid), originId, namespace);
        return pidUri;
    }

    public String postPidAndPersonaIfNotExisted(String email, String password) throws Exception {
        String originId = TestUtil.getRandomOriginId();
        return postPidAndPersonaIfNotExisted(email, password, originId, "cem_ea_id");
    }

    public String postPidIfNotExisted(String email, String password) throws Exception {
        return postPidIfNotExisted(email, password, PasswordStrength.STRONG);
    }

    public String postPidIfNotExisted(String email, String password, PasswordStrength strength) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();

        PidSearchApiRequest pidSearchApiRequest = new PidSearchApiRequest();
        pidSearchApiRequest.setEmail(email);
        PidSearchApiResponse pidSearchApiResponse = identityClientApi.executePidSearch(pidSearchApiRequest);
        if (pidSearchApiResponse.getPids().getPidUri() != null) {
            return pidSearchApiResponse.getPids().getPidUri().get(0);
        }
        return postPid(email, password, strength);
    }

    public void postPrivacySettings(String pid) throws Exception {
        PrivacySettingsPostApiRequest request = new PrivacySettingsPostApiRequest();
        request.setPidId(pid);
        request.setX_Source("Integration-Tests");
        pidPrivacySettingsType privacySettingsType = new pidPrivacySettingsType();
        privacySettingsType.setShowRealName("EVERYONE");
        privacySettingsType.setFacebookDiscoverable("EVERYONE");
        privacySettingsType.setPsnIdDiscoverable("EVERYONE");
        privacySettingsType.setShareAchievements("EVERYONE");
        privacySettingsType.setXboxTagDiscoverable("EVERYONE");
        request.setPrivacySettings(privacySettingsType);
        PrivacySettingsPostApiResponse response = getIdentityClientApi().executePrivacySettingsPost(request);
        if (response.getHttpResponseCode() != 201) {
            throw new Exception("post privacy settings failed");
        }
    }

    public void postPrivacySettingsIfNotExists(String pid) throws Exception {
        PrivacySettingsGetApiRequest request = new PrivacySettingsGetApiRequest();
        request.setPidId(pid);
        request.setNucleus_RequestorId("Integration-Tests");
        PrivacySettingsGetApiResponse response = getIdentityClientApi().executePrivacySettingsGet(request);
        if (response != null && response.getPidPrivacySettings() != null) {
            return;
        }
        postPrivacySettings(pid);
    }

    public void putPidStatus(Long pid, String newStatus) throws Exception {
        HttpPut httpPut = new HttpPut(SystemProperties.instance().getProperty(SystemProperties.IdentityPortalUri) + "/pids/" + pid);
        httpPut.setEntity(new StringEntity("{\"status\":\"" + newStatus + "\"}"));
        httpPut.setHeader("Nucleus-RequestorId", "Integration-Tests");
        httpPut.setHeader("X-Include-Underage", "true");
        HttpResponse response = client.execute(httpPut);
        if (response.getStatusLine().getStatusCode() != 200) {
            throw new Exception(IOUtils.toString(response.getEntity().getContent()));
        }
    }

    public void putPidPassword(Long pid, String oldPassword, String newPassword) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();
        UpdatePidApiRequest updatePidApiRequest = new UpdatePidApiRequest();
        updatePidApiRequest.setPidId(pid);

        PidType pidType = new PidType();
        pidType.setCurrentPassword(oldPassword);
        pidType.setPassword(newPassword);
        updatePidApiRequest.setPid(pidType);

        UpdatePidApiResponse updatePidApiResponse = identityClientApi.executeUpdatePid(updatePidApiRequest);
        if (updatePidApiResponse.getHttpResponseCode() != 200)
            throw new Exception("not update success");
    }

    public void putPidEmailStatus(Long pid, String newStatus) throws Exception {
        HttpPut httpPut = new HttpPut(SystemProperties.instance().getProperty(SystemProperties.IdentityPortalUri) + "/pids/" + pid);
        httpPut.setEntity(new StringEntity("{\"emailStatus\":\"" + newStatus + "\"}"));
        httpPut.setHeader("Nucleus-RequestorId", "Integration-Tests");
        httpPut.setHeader("X-Include-Underage", "true");
        HttpResponse response = client.execute(httpPut);
        if (response.getStatusLine().getStatusCode() != 200) {
            throw new Exception(IOUtils.toString(response.getEntity().getContent()));
        }
    }

    public void putPersonaStatus(Long pid, Long personaId, String newStatus) throws Exception {
        HttpPut httpPut = new HttpPut(SystemProperties.instance().getProperty(SystemProperties.IdentityPortalUri) + "/pids/" + pid + "/personas/" + personaId);
        httpPut.setEntity(new StringEntity("{\"status\":\"" + newStatus + "\"}"));
        httpPut.setHeader("Nucleus-RequestorId", "Integration-Tests");
        httpPut.setHeader("X-Include-Underage", "true");
        HttpResponse response = client.execute(httpPut);
        if (response.getStatusLine().getStatusCode() != 200) {
            throw new Exception(IOUtils.toString(response.getEntity().getContent()));
        }
    }

    public void putEmailToAnotherIfExisted(String email) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();

        PidSearchApiRequest pidSearchApiRequest = new PidSearchApiRequest();
        pidSearchApiRequest.setEmail(email);

        PidSearchApiResponse pidSearchApiResponse = identityClientApi.executePidSearch(pidSearchApiRequest);
        if (pidSearchApiResponse.getPids().getPidUri() != null) {
            String pidUri = pidSearchApiResponse.getPids().getPidUri().get(0);
            String pid = pidUri.split("/")[2];
            UpdatePidApiRequest updatePidApiRequest = new UpdatePidApiRequest();
            updatePidApiRequest.setPidId(Long.parseLong(pid));

            PidType pidType = new PidType();
            pidType.setEmail(TestUtil.getRandomEmail());
            updatePidApiRequest.setPid(pidType);

            UpdatePidApiResponse updatePidApiResponse = identityClientApi.executeUpdatePid(updatePidApiRequest);
            if (updatePidApiResponse.getHttpResponseCode() != 200)
                throw new Exception("not update success");
        }
    }

    public String getSecurityState(String email) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();

        PidSearchApiRequest pidSearchApiRequest = new PidSearchApiRequest();
        pidSearchApiRequest.setEmail(email);
        pidSearchApiRequest.setX_Expand_Results(true);
        PidSearchApiResponse pidSearchApiResponse = identityClientApi.executePidSearch(pidSearchApiRequest);
        Long pid = pidSearchApiResponse.getPids().getPid().get(0).getPidId();

        PidGetSecuritystateApiRequest request = new PidGetSecuritystateApiRequest();
        request.setPidId(pid);
        request.setNucleus_AdminUserId("dev");

        PidGetSecuritystateApiResponse response = identityClientApi.executePidGetSecuritystate(request);
        return response.getSecurityState().getAuthentication().getState();
    }

    public List<String> searchEmailPreferences(String email) throws Exception {
        SearchEmailPreferencesApiRequest request = new SearchEmailPreferencesApiRequest();
        request.setEmail(email);

        IdentityClientApi identityClientApi = getIdentityClientApi();
        SearchEmailPreferencesApiResponse response = identityClientApi.executeSearchEmailPreferences(request);
        if (response.getHttpResponseCode() != 200)
            throw new Exception("search email preferences failed");
        else {
            return response.getEmailPreferenceLinks().getEmailPreferenceLinkUri();
        }
    }

    public void putDOB(Long pidId, String dob) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();
        UpdatePidApiRequest updatePidApiRequest = new UpdatePidApiRequest();
        updatePidApiRequest.setPidId(pidId);
        updatePidApiRequest.setX_Include_Underage(true);

        PidType pidType = new PidType();
        pidType.setDob(dob);

        updatePidApiRequest.setPid(pidType);

        UpdatePidApiResponse updatePidApiResponse = identityClientApi.executeUpdatePid(updatePidApiRequest);
        if (updatePidApiResponse.getHttpResponseCode() != 200)
            throw new Exception("not update success");
    }
    public PidType getPid(Long pid) {
        PidGetApiRequest pidGetApiRequest = new PidGetApiRequest();
        pidGetApiRequest.setPidId(pid);
        return getIdentityClientApi().executePidGet(pidGetApiRequest).getPid();
    }

    public PidType getIncompletePid(Long pid) {
        IdentityClientApi identityClientApi= getIdentityClientApi();
        identityClientApi.getDefaultHeaderMap().put("X-Include-Incomplete","true");
        PidGetApiRequest pidGetApiRequest = new PidGetApiRequest();
        pidGetApiRequest.setPidId(pid);
        return identityClientApi.executePidGet(pidGetApiRequest).getPid();
    }

    public Long getPidID(String pidUri) {
        String[] params = pidUri.split("/");
        return Long.parseLong(params[params.length - 1]);
    }

    public Long getPersonaID(String personaUri) {
        String[] params = personaUri.split("/");
        return Long.parseLong(params[params.length - 1]);
    }

    public String getUserVerifyCode(long pid,String platform,String clientId) {
        IdentityClientApi identityClientApi= getIdentityClientApi();
        identityClientApi.getDefaultHeaderMap().put("Client-Id",clientId);
        UserverifycodeGetApiRequest request = new UserverifycodeGetApiRequest();
        request.setPlatform(platform);
        request.setPidId(pid);

        return identityClientApi.executeUserverifycodeGet(request).getUserVerifyCode();

    }

    public String getTwoFactorCode(long pid) {
        TwoFactorType tfa = getTwoFactor(pid);
        if (tfa.getCodeType().equalsIgnoreCase("APP")) {
            CalculateTwoFactorCodeWorkflowElement calculateTfaCode = new CalculateTwoFactorCodeWorkflowElement();
            calculateTfaCode.input.codeType = tfa.getCodeType();
            calculateTfaCode.input.securityKey = tfa.getSecretKey();
            calculateTfaCode.execute();

            return calculateTfaCode.output.code;
        } else {
            TwofactorcodeGetApiRequest twofactorcodeGetApiRequest = new TwofactorcodeGetApiRequest();
            twofactorcodeGetApiRequest.setPidId(String.valueOf(pid));
            return getIdentityClientApi().executeTwofactorcodeGet(twofactorcodeGetApiRequest).getTwoFactorCode();
        }
    }

    public String getTwoFactorCodeForSetup(long pid, String twoFactorType,String regionCode, String phoneNumber, String email) {
        if (twoFactorType.equalsIgnoreCase("APP")) {
            TwoFactorType tfa = getTwoFactor(pid);

            CalculateTwoFactorCodeWorkflowElement calculateTfaCode = new CalculateTwoFactorCodeWorkflowElement();
            calculateTfaCode.input.codeType = twoFactorType;
            calculateTfaCode.input.securityKey = tfa.getSecretKey();
            calculateTfaCode.execute();

            return calculateTfaCode.output.code;
        } else {
            TwofactorcodeGetApiRequest twofactorcodeGetApiRequest = new TwofactorcodeGetApiRequest();
            twofactorcodeGetApiRequest.setPidId(String.valueOf(pid));
            twofactorcodeGetApiRequest.setX_Twofactor_Code_For_Setup(true);
            twofactorcodeGetApiRequest.setCodeType(twoFactorType);
            if (regionCode != null && !regionCode.isEmpty())
                twofactorcodeGetApiRequest.setRegionCode(regionCode);
            if (phoneNumber != null && !phoneNumber.isEmpty())
                twofactorcodeGetApiRequest.setPhoneNumber(phoneNumber);
            if (email != null && !email.isEmpty())
                twofactorcodeGetApiRequest.setEmail(email);
            twofactorcodeGetApiRequest.setX_Skip_Phone_Validation(true);
            TwofactorcodeGetApiResponse twofactorcodeGetApiResponse = getIdentityClientApi().executeTwofactorcodeGet(twofactorcodeGetApiRequest);

            return twofactorcodeGetApiResponse.getTwoFactorCode();
        }
    }

    public String getTwoFactorBackupCode(long pid) {
        return getTwoFactorBackupCode(pid, false);
    }

    public Map<String, Boolean> getTwoFactorBackupCodesWithExpirationInfo(long pid) {
        TwofactorbackupcodeGetApiRequest twofactorbackupcodeGetApiRequest = new TwofactorbackupcodeGetApiRequest();
        twofactorbackupcodeGetApiRequest.setPidId(String.valueOf(pid));
        TwofactorbackupcodeGetApiResponse twofactorbackupcodeGetApiResponse = getIdentityClientApi().executeTwofactorbackupcodeGet(twofactorbackupcodeGetApiRequest);
        List<TwoFactorBackupCodeType> codes = twofactorbackupcodeGetApiResponse.getBackupCodes().getBackupCode();

        Map<String, Boolean> result = new HashMap<String, Boolean>();

        for (TwoFactorBackupCodeType code : codes)
            result.put(code.getCode(), "Y".equals(code.getIsExpired()));

        return result;
    }

    public String getTwoFactorBackupCode(long pid, boolean isCodeExpired) {
        Map<String, Boolean> codes = getTwoFactorBackupCodesWithExpirationInfo(pid);

        for (Map.Entry<String, Boolean> code : codes.entrySet()) {
            if (code.getValue().equals(isCodeExpired)) {
                return code.getKey();
            }
        }

        return isCodeExpired ? null : postTwoFactorBackupCode(pid).getBackupCode().get(0).getCode();
    }

    public BackupCodesType postTwoFactorBackupCode(long pid) {
        TwofactorbackupcodePostApiRequest twofactorbackupcodePostApiRequest = new TwofactorbackupcodePostApiRequest();
        twofactorbackupcodePostApiRequest.setPidId(String.valueOf(pid));
        return getIdentityClientApi().executeTwofactorbackupcodePost(twofactorbackupcodePostApiRequest).getBackupCodes();
    }

    public TwoFactorType getTwoFactor(long pid) {
        TwofactorGetApiRequest twofactorGetApiRequest = new TwofactorGetApiRequest();
        twofactorGetApiRequest.setPidId(String.valueOf(pid));
        return getIdentityClientApi().executeTwofactorGet(twofactorGetApiRequest).getTwoFactor();
    }

    public String getTwoFactorStatus(long pid) {
        return getTwoFactor(pid).getStatus();
    }

    public void putTwoFactorStatus(long pid, String statusToPut) {
        TwofactorstatusPutApiRequest twofactorstatusPutApiRequest = new TwofactorstatusPutApiRequest();
        twofactorstatusPutApiRequest.setPidId(String.valueOf(pid));
        TwoFactorStatusType twoFactorStatusType = new TwoFactorStatusType();
        twoFactorStatusType.setStatus(statusToPut);
        twofactorstatusPutApiRequest.setPayload(twoFactorStatusType);
        getIdentityClientApi().executeTwofactorstatusPut(twofactorstatusPutApiRequest);
    }

    public String verifyTwoFactorCode(long pid, String code) {
        TwofactorcodeVerifyApiRequest twofactorcodeVerifyApiRequest = new TwofactorcodeVerifyApiRequest();
        twofactorcodeVerifyApiRequest.setPidId(String.valueOf(pid));
        TwoFactorVerifyCodeRequestType twoFactorVerifyCodeRequestType = new TwoFactorVerifyCodeRequestType();

        twoFactorVerifyCodeRequestType.setCode(code);
        twofactorcodeVerifyApiRequest.setPayload(twoFactorVerifyCodeRequestType);
        return getIdentityClientApi().executeTwofactorcodeVerify(twofactorcodeVerifyApiRequest).getCodeStatus();
    }

    private String verifyTwoFactorCodeForSetup(long pid, String twoFactorType,String code,String regionCode, String phoneNumber, String email) {
        TwofactorcodeVerifyApiRequest twofactorcodeVerifyApiRequest = new TwofactorcodeVerifyApiRequest();
        twofactorcodeVerifyApiRequest.setPidId(String.valueOf(pid));
        if (!twoFactorType.equalsIgnoreCase("APP")) {
            twofactorcodeVerifyApiRequest.setX_Twofactor_Code_For_Setup(true);
        }
        TwoFactorVerifyCodeRequestType twoFactorVerifyCodeRequestType = new TwoFactorVerifyCodeRequestType();

        twoFactorVerifyCodeRequestType.setCode(code);
        if(regionCode!=null&&!regionCode.isEmpty())
            twoFactorVerifyCodeRequestType.setRegionCode(regionCode);
        if(phoneNumber!=null&&!phoneNumber.isEmpty())
            twoFactorVerifyCodeRequestType.setPhoneNumber(phoneNumber);
        if(email!=null&&!email.isEmpty())
            twoFactorVerifyCodeRequestType.setEmail(email);
        twoFactorVerifyCodeRequestType.setCodeType(twoFactorType);
        twofactorcodeVerifyApiRequest.setPayload(twoFactorVerifyCodeRequestType);
        TwofactorcodeVerifyApiResponse twofactorcodeVerifyApiResponse = getIdentityClientApi().executeTwofactorcodeVerify(twofactorcodeVerifyApiRequest);
        return twofactorcodeVerifyApiResponse.getCodeStatus();
    }

    public void postToEnableTwoFactorIfNotExisted(long pid) throws Exception {
        postToEnableTwoFactorIfNotExisted(pid, "Email");
    }

    public void postToEnableTwoFactorIfNotExisted(long pid, String twofactorType) throws Exception {
        String status = null;
        try {
            status = getTwoFactorStatus(pid);
        } catch (Exception ex) {
            // ignore if twofactor cannot be get.
        }
        if (status == null) {
            if (twofactorType != null && twofactorType.equalsIgnoreCase("sms")) {
                postToEnableTwoFactorWithSMS(pid, TestUtil.getRandomDigits(16));
            } else {
                postToEnableTwoFactor(pid, twofactorType);
            }
        } else {
            if (!status.equalsIgnoreCase("ENABLED")) {
                throw new Exception(String.format("The twofactor of pid:%s is not Enabled.", pid));
            }
        }
    }

    public void postToEnableTwoFactorIfNotExistedSms(long pid, String phoneNumber) throws Exception {
        String status = null;
        try {
            status = getTwoFactorStatus(pid);
        } catch (Exception ex) {
            // ignore if twofactor cannot be get.
        }
        if (status == null) {
            postToEnableTwoFactorWithSMS(pid, phoneNumber);
        } else {
            if (!status.equalsIgnoreCase("ENABLED")) {
                throw new Exception(String.format("The twofactor of pid:%s is not Enabled.", pid));
            }
        }
    }

    private void postToEnableTwoFactor(long pid, String twofactorType) throws Exception {
        TwofactorPostApiRequest twofactorPostApiRequest = new TwofactorPostApiRequest();
        TwoFactorPostRequestType twoFactorPostRequestType = new TwoFactorPostRequestType();
        twoFactorPostRequestType.setCodeType(twofactorType);
        twofactorPostApiRequest.setPayload(twoFactorPostRequestType);
        postToEnableTwoFactorInternal(pid, twofactorPostApiRequest);
    }

    public void postToDisableTwoFactor(long pid, String twofactorType) throws Exception {
        postToEnableTwoFactor(pid, twofactorType);
        putTwoFactorStatus(pid, "DISABLED");
        TestUtil.verifyEqual(getTwoFactorStatus(pid), "DISABLED", "verify twofactor by code to DISABLED status");
    }

    private void postToEnableTwoFactorWithSMS(long pid, String phoneNumber) throws Exception {
        TwofactorPostApiRequest twofactorPostApiRequest = new TwofactorPostApiRequest();
        TwoFactorPostRequestType twoFactorPostRequestType = new TwoFactorPostRequestType();
        twoFactorPostRequestType.setCodeType("SMS");
        twoFactorPostRequestType.setRegionCode(defaultRegionCode);
        twoFactorPostRequestType.setPhoneNumber(phoneNumber);
        twofactorPostApiRequest.setPayload(twoFactorPostRequestType);
        postToEnableTwoFactorInternal(pid, twofactorPostApiRequest);
    }

    private void postToEnableTwoFactorInternal(long pid, TwofactorPostApiRequest twofactorPostApiRequest) throws Exception {
        String pidId = String.valueOf(pid);
        IdentityClientApi identityClientApi = getIdentityClientApi();
        twofactorPostApiRequest.setPidId(pidId);
        twofactorPostApiRequest.setX_Skip_Phone_Validation(true);
        identityClientApi.executeTwofactorPost(twofactorPostApiRequest);
        TwoFactorType twoFactorType = getTwoFactor(pid);
        TestUtil.verifyEqual(twoFactorType.getStatus(), "PENDING", "post twofactor to PENDING status");
        String code = getTwoFactorCodeForSetup(pid,twoFactorType.getCodeType(),twoFactorType.getRegionCode(),twoFactorType.getPhoneNumber(),twoFactorType.getEmail());
        String codeStatus = verifyTwoFactorCodeForSetup(pid, twoFactorType.getCodeType(),code,twoFactorType.getRegionCode(),twoFactorType.getPhoneNumber(),twoFactorType.getEmail());
        TestUtil.verifyEqual(codeStatus, "VALID", "verify code status");
        TestUtil.verifyEqual(getTwoFactorStatus(pid), "VERIFIED", "verify twofactor by code to VERIFIED status");
        putTwoFactorStatus(pid, "ENABLED");
        TestUtil.verifyEqual(getTwoFactorStatus(pid), "ENABLED", "verify twofactor by code to ENABLED status");
    }

    public TwoPhaseRegistrationRecordType getTwoPhaseRegistrationRecord(Long pidId) throws Exception {
        UsercodeGetByUseridApiRequest userCoderequest = new UsercodeGetByUseridApiRequest();
        userCoderequest.setPidId(pidId);
        userCoderequest.setCodeType("Register");
        UsercodeGetByUseridApiResponse userCoderesponse = getIdentityClientApi().executeUsercodeGetByUserid(userCoderequest);
        if (userCoderesponse.getHttpResponseCode() != 200) {
            throw new Exception("get two phase registration code failed");
        }
        UserCodeRecordType userCodeRecordType = userCoderesponse.getUserCodeRecord();
        TwoPhaseRegistrationRecordType record = new TwoPhaseRegistrationRecordType();
        record.setUserId(userCodeRecordType.getUserId());
        record.setStatus(userCodeRecordType.getStatus());
        record.setRegistrationCode(userCodeRecordType.getCode());
        return record;
    }

    public PidType getUnderageUser(Long pid) {
        PidGetApiRequest pidGetApiRequest = new PidGetApiRequest();
        pidGetApiRequest.setX_Include_Underage(true);
        pidGetApiRequest.setPidId(pid);
        return getIdentityClientApi().executePidGet(pidGetApiRequest).getPid();
    }

    public PidType getIncompleteUser(Long pid) {
        PidGetApiRequest pidGetApiRequest = new PidGetApiRequest();
        pidGetApiRequest.setX_Include_Underage(true);
        pidGetApiRequest.setPidId(pid);
        return getIdentityClientApi().executePidGet(pidGetApiRequest).getPid();
    }

    public PsnrefreshtokenPostApiResponse postPersonaPSNRefreshtoken(String personaId, String psnRefreshToken, String platform, String sonyS2SClientIdVersion)
    {
        PsnrefreshtokenPostApiRequest postApiRequest = new PsnrefreshtokenPostApiRequest();
        postApiRequest.setPersonaId(personaId);
        PSNRefreshTokenRequestType psnRefreshTokenRequestType = new PSNRefreshTokenRequestType();
        psnRefreshTokenRequestType.setPlatform(platform);
        psnRefreshTokenRequestType.setPsnRefreshToken(psnRefreshToken);
        postApiRequest.setPayload(psnRefreshTokenRequestType);
        return getIdentityClientApi().executePsnrefreshtokenPost(postApiRequest);
    }

    public List<String> getUserOptins(Long pid) throws Exception {
        String baseUrl = SystemProperties.instance().getProperty(SystemProperties.IdentityPortalUri);
        String url = baseUrl + String.format("/pids/%1$s/optins", pid);
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Nucleus-RequestorId", "Integration-Tests");
        HttpResponse response = get(httpGet, null);

        String body = IOUtils.toString(response.getEntity().getContent());
        log.info("RESPONSE BODY: " + body);

        List<String> listOptins = new ArrayList<String>();

        if(body != null && body.indexOf("optin") > 0 && body.indexOf("[") > 0) {
            String[] strOptins = body.substring(body.indexOf("[") + 1,body.indexOf("]")).split(",");

            for(String optin : strOptins){
                listOptins.add(optin.replace("\"", "").trim());
            }
        }

        return listOptins;
    }

    public String getUserCodeByPid(final Long pid, final String codeType) throws Exception {
        IdentityClientApi identityClientApi = getIdentityClientApi();
        UsercodeGetByUseridApiRequest request = new UsercodeGetByUseridApiRequest();
        request.setPidId(pid);
        request.setCodeType(codeType);
        UsercodeGetByUseridApiResponse response = identityClientApi.executeUsercodeGetByUserid(request);
        return response.getUserCodeRecord().getCode();
    }


}
